package br.com.folha.controller;

import br.com.folha.dao.GenericoDao;
import br.com.folha.dao.GrupoDao;
import br.com.folha.dao.UnidadeDao;
import br.com.folha.dao.UsuarioDao;
import br.com.folha.entity.Grupo;
import br.com.folha.entity.Unidade;
import br.com.folha.entity.Usuario;
import br.com.folha.utilidades.utilidades;
import java.io.Serializable;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
 
@ManagedBean(name="UsuarioController")
@ViewScoped
public class UsuarioController implements Serializable {
 
    private static final long serialVersionUID = -5140496153854040344L;
    private Usuario usuario;
    private Usuario usuarioSelecionado;
    private GenericoDao usuarioDao = new GenericoDao();   
    
    private Unidade unidade;
    private UnidadeDao unidadeDao = new UnidadeDao();
        
    private Boolean[] ativoSelecionado;
    private Map<String,Integer> unidades;         
    private List<String> selectedUnidades;    
    private List<Unidade> retornoUnidades;     
    
    private transient DataModel lista;
    private String acao;
    private Usuario resultado;
    private Date data = new Date();
    private boolean retorno;
    
    private Grupo grupo;
    private GrupoDao grupoDao = new GrupoDao();
    private Integer selectedGrupo;
    
    /*
     * Para tratamento da senha eu realizei o seguinte procedimento :
     * Ao incluir um usuário deve ser informada a senha e antes da inclusão da linha no BD
     * a senha é criptografada;
     * Ao alterar um usuário a senha é carregada na variável abaixo, senhaCriptografada
     * que é um campo hidden da tela, dessa forma é realizado o seguinte procedimento :
     * Caso o usuário deseje alterar a senha, deverá informa a nova senha e na hora de 
     * incluir o registro no BD essa senha é criptografada e salva no banco, caso o usuário
     * não deseje alterar a senha atual, como o campo senha estará vazio será utilizado o campo
     * hidden que já estará com a senha criptografada para o update do registro em questão.
     */
    private String senhaCriptografada;
 
    public UsuarioController() {
        
        usuario = new Usuario();        
        populaSelectUnidade();       
        
        acao = "";
        
    }   
    
    public void preparaInclusao(){
               
        FacesMessage msg = null;        
        FacesContext context = FacesContext.getCurrentInstance();
        
        if(usuario.getNome().equals("")){
                        
            msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "O nome do usuário deve ser informado", "");
            context.getCurrentInstance().addMessage(null, msg);
            
        }if(usuario.getLogin().equals("")){
                                    
            msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "O login do usuário deve ser informado", "");
            context.getCurrentInstance().addMessage(null, msg);            
                    
        }else{
            
            if(!acao.equals("edicao")){
                                
                    UsuarioDao consulta = new UsuarioDao();
                    resultado = consulta.consultaUsuario(usuario.getLogin());
                    
                    if(resultado == null){
                        salvaOperacao();
                        resetUsuario();
                    }else{
                        msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Já existe um usuário com esse login", "");
                        context.getCurrentInstance().addMessage(null, msg);
                    }
            
            }else{
                
                editaUsuario();
                acao = "";
            }
            
        }        
        
    } 
    
    public void salvaOperacao(){
        
        FacesMessage msg = null;
        FacesContext context = FacesContext.getCurrentInstance();   
        
        this.usuario.setDt_cadastro(data); 
        
        utilidades utilidades = new utilidades();
        try {
            this.usuario.setSenha(utilidades.criptografaSenha(this.usuario.getSenha()));
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(UsuarioController.class.getName()).log(Level.SEVERE, null, ex);
        }                        
        
        LoginController usuarioLogado = new LoginController();
                
        this.usuario.setUsuario_cadastro(usuarioLogado.Usuario.getId());  
        
        this.usuario.setDt_cadastro(data);
        
        Set<Unidade> unidades = new HashSet<Unidade>();
        //For utilizado para varrer os itens selecionados no select de Unidades
        for (int i = 0; i < this.selectedUnidades.size(); i++){                         
            
            Integer codigo = Integer.parseInt(this.selectedUnidades.get(i));
            
            Unidade unidadeTeste = new Unidade();            
            unidadeTeste = unidadeDao.getById(codigo);
                        
            unidades.add(unidadeTeste);            
                                    
            this.usuario.setUnidades(unidades);
        }

        /*
         * Este bloco realiza a inclusão do usuário no Grupo selecionado
         * e no grupo Role_User que é o padrão para todos os usuários
         */
        
            Grupo retornoGrupo = new Grupo();            
            
            retornoGrupo = grupoDao.getById(this.selectedGrupo);            
        
        this.usuario.setGrupo(retornoGrupo.getId());
        
        /*
         * Fim do bloco de inclusão de usuários nos grupos
         */
        
        retorno = usuarioDao.salvar(this.usuario);
        
        lista = new ListDataModel(usuarioDao.listar(usuario));
        
        if(retorno){
            msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Usuário cadastrado com sucesso!", "");
            FacesContext.getCurrentInstance().addMessage(null, msg);
        }else{
            msg = new FacesMessage(FacesMessage.SEVERITY_FATAL, "Falha ao salvar usuário!", "");
            FacesContext.getCurrentInstance().addMessage(null, msg);            
        }
        
    }    
    
    public void editaUsuario(){
        
        FacesMessage msg = null;
        FacesContext context = FacesContext.getCurrentInstance();  
                
        if(usuario.getNome().equals("")){
                        
            msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "O nome do usuário deve ser informado", "");
            context.getCurrentInstance().addMessage(null, msg);
            
        }if(usuario.getLogin().equals("")){
                                    
            msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "O login do usuário deve ser informado", "");
            context.getCurrentInstance().addMessage(null, msg);                          
            
        }if(this.selectedUnidades.size() == 0){
            
            msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "O usuário deve pertencer a pelo menos uma unidade! Caso o usuário não pertença a nenhuma unidade, o mesmo deverá ser excluído.", "");
            context.getCurrentInstance().addMessage(null, msg);               
            
        }else{
        
                usuario.setDt_atualizacao(data);    
                
                String senha = this.usuario.getSenha();                                
                
                if(senha != null && senha.trim().length() == 0){
                    this.usuario.setSenha(this.senhaCriptografada);                
                }else{
                    utilidades utilidades = new utilidades();
                    try {
                        this.usuario.setSenha(utilidades.criptografaSenha(this.usuario.getSenha()));
                    } catch (NoSuchAlgorithmException ex) {
                        Logger.getLogger(UsuarioController.class.getName()).log(Level.SEVERE, null, ex);
                    }                    
                }                                

                LoginController usuarioLogado = new LoginController();

                usuario.setUsuario_atualizacao(usuarioLogado.Usuario.getId());

                Set<Unidade> unidades = new HashSet<Unidade>();
                //For utilizado para varrer os itens selecionados no select de Unidades
                for (int i = 0; i < this.selectedUnidades.size(); i++){                         

                    Integer codigo = Integer.parseInt(this.selectedUnidades.get(i));

                    Unidade unidadeTeste = new Unidade();            
                    unidadeTeste = unidadeDao.getById(codigo);                                  

                    unidades.add(unidadeTeste);            

                    this.usuario.setUnidades(unidades);
                }      

                Grupo retornoGrupo = new Grupo();            

                retornoGrupo = grupoDao.getById(this.selectedGrupo);            

                this.usuario.setGrupo(retornoGrupo.getId());                        

                retorno = usuarioDao.atualizar(usuario); 

                resetUsuario();

                lista = new ListDataModel(usuarioDao.listar(usuario));

                if(retorno){           

                    msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Usuário atualizado com sucesso!", "");
                    FacesContext.getCurrentInstance().addMessage(null, msg);

                }          
        
        }
        
    }   
    
    public Usuario preparaEdicao(){
        
        FacesMessage msg = null;
        
        int contador = 0;
        this.selectedUnidades.clear();
        
        this.senhaCriptografada = this.usuarioSelecionado.getSenha();                        
        
        for (Iterator iterator = this.usuarioSelecionado.getUnidades().iterator(); iterator.hasNext();){
            
            Unidade unidade = (Unidade) iterator.next();                                                                 
            
            this.selectedUnidades.add(contador,unidade.getId().toString());            
                        
        } 
        
        if(this.usuarioSelecionado.getGrupo() == null){
            
            getCarregarSelect();
            
        }else{
        
            this.selectedGrupo = this.usuarioSelecionado.getGrupo();
        
        }        
        
        if(this.usuarioSelecionado == null){
            
            msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Selecione o usuário a ser editado!", "");
            FacesContext.getCurrentInstance().addMessage(null, msg);            
            
        }else{                        
            
            this.usuario = this.usuarioSelecionado;                        
            
            acao = "edicao";
        
        }
        
      return usuario;
    }    
    
    public void deleteUsuario(){
        
        FacesMessage msg = null;
        FacesContext context = FacesContext.getCurrentInstance();
        
        LoginController usuarioLogado = new LoginController();                    
            
        if(this.usuarioSelecionado == null){
            
            msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Selecione o usuário a ser deletado!", "");
            context.getCurrentInstance().addMessage(null, msg); 
            
        }else if(this.usuarioSelecionado.getId().equals(usuarioLogado.Usuario.getId())){            
            msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Não é permitido exluir o usuário corrente!", "");
            context.getCurrentInstance().addMessage(null, msg);             
            
        }else{
        
            usuarioDao.excluir(this.usuarioSelecionado);
            resetUsuario();
            lista = new ListDataModel(usuarioDao.listar(getUsuario()));
            
        }
        
    }    
    
    public void resetUsuario(){
        usuario = new Usuario();        
        populaSelectUnidade();
        getCarregarSelect();
        this.selectedUnidades.clear();
        this.selectedGrupo = null;
        acao = "";
    }
    
    public void populaSelectUnidade(){
        
        setUnidades(new HashMap<String,Integer>()); 
        
        unidade = new Unidade();
        
        LoginController usuarioLogado = new LoginController();
        
        List<Integer> integerArray = new ArrayList<Integer>();
        
        LoginController login = new LoginController();
        
        if(login.isUsuAdm()){                        
            
            for (Iterator iterator = usuarioDao.listar(unidade).iterator(); iterator.hasNext();){

                Unidade unidade = (Unidade) iterator.next();                     

                integerArray.add(unidade.getId());

            }            
            
        }else{
        
            for (Iterator iterator = usuarioLogado.Usuario.getUnidades().iterator(); iterator.hasNext();){

                Unidade unidade = (Unidade) iterator.next();                     

                integerArray.add(unidade.getId());

            }     
        
        }
        
        retornoUnidades = unidadeDao.listaUnidade(unidade,integerArray);
        
        for (Iterator iterator = retornoUnidades.iterator(); iterator.hasNext();){
            
            Unidade unidade = (Unidade) iterator.next();                     
            
            getUnidades().put(unidade.getNome(), unidade.getId());                                
        
        }         
        
    } 
    
  public Collection<SelectItem> getCarregarSelect() {        
      
      grupo = new Grupo();
      
        Collection<SelectItem> lst = new ArrayList<SelectItem>();        
        lst.add(new SelectItem(null, "Selecione o Grupo"));      //Primeiro item do select   
        List<Grupo> lista = grupoDao.listaGrupo(grupo);
        for (int i = 0; i < lista.size(); i++) {          
            lst.add(new SelectItem(lista.get(i).getId(), lista.get(i).getNome()));              
        }          
        return lst;          
    }     

    public DataModel getLista() {
        if(lista == null || lista.getRowCount() == 0){
            
            lista = new ListDataModel(usuarioDao.listar(getUsuario()));
        }
        
        return lista;
    }

    public Usuario getUsuario() {
        return usuario;
    }

    public void setUsuario(Usuario usuario) {
        this.usuario = usuario;
    }

    public Map<String,Integer> getUnidades() {
        return unidades;
    }

    public void setUnidades(Map<String,Integer> unidades) {
        this.unidades = unidades;
    }

    public List<String> getSelectedUnidades() {
        return selectedUnidades;
    }

    public void setSelectedUnidades(List<String> selectedUnidades) {
        this.selectedUnidades = selectedUnidades;
    }

    public Boolean[] getAtivoSelecionado() {
        return ativoSelecionado;
    }

    public void setAtivoSelecionado(Boolean[] ativoSelecionado) {
        this.ativoSelecionado = ativoSelecionado;
    }

    public Usuario getUsuarioSelecionado() {
        return usuarioSelecionado;
    }

    public void setUsuarioSelecionado(Usuario usuarioSelecionado) {
        this.usuarioSelecionado = usuarioSelecionado;
    }

    /**
     * @return the selectedGrupo
     */
    public Integer getSelectedGrupo() {
        return selectedGrupo;
    }

    /**
     * @param selectedGrupo the selectedGrupo to set
     */
    public void setSelectedGrupo(Integer selectedGrupo) {
        this.selectedGrupo = selectedGrupo;
    }

    /**
     * @return the senhaCriptografada
     */
    public String getSenhaCriptografada() {
        return senhaCriptografada;
    }

    /**
     * @param senhaCriptografada the senhaCriptografada to set
     */
    public void setSenhaCriptografada(String senhaCriptografada) {
        this.senhaCriptografada = senhaCriptografada;
    }
                   
}